"""
索引类型定义和常量

定义索引系统使用的数据类型和常量
"""

import struct
from enum import Enum
from typing import Any, Union, List, Optional
from dataclasses import dataclass


class IndexType(Enum):
    """索引类型枚举"""
    PRIMARY = "primary"      # 主键索引（聚簇）
    UNIQUE = "unique"        # 唯一索引
    NORMAL = "normal"        # 普通索引
    HASH = "hash"           # 哈希索引


class PageType(Enum):
    """页面类型枚举"""
    DATA = 0x01             # 数据页面
    INDEX_INTERNAL = 0x02   # 索引内部节点页面
    INDEX_LEAF = 0x03       # 索引叶子节点页面
    FREE = 0x04             # 空闲页面


# 索引相关常量
INDEX_CONSTANTS = {
    'PAGE_SIZE': 4096,
    'PAGE_HEADER_SIZE': 32,           # 页面头部大小
    'INDEX_HEADER_SIZE': 24,          # 索引头部大小
    'BTREE_ORDER': 128,               # B+树的阶数（最大键数）
    'MIN_KEYS': 64,                   # 最小键数（阶数的一半）
    'KEY_SIZE': 8,                    # 键的固定大小（支持整数和字符串哈希）
    'POINTER_SIZE': 4,                # 页面指针大小
    'RECORD_ID_SIZE': 8,              # 记录ID大小（页面ID + 页内偏移）
}


@dataclass
class IndexKey:
    """索引键定义"""
    value: Any                        # 键值
    key_type: str                     # 键类型 ('int', 'string', 'float')
    
    def to_bytes(self) -> bytes:
        """将键转换为固定长度的字节序列"""
        if self.key_type == 'int':
            return struct.pack('<Q', int(self.value))  # 8字节无符号整数
        elif self.key_type == 'float':
            return struct.pack('<d', float(self.value))  # 8字节双精度浮点数
        elif self.key_type == 'string':
            # 字符串使用哈希值存储，保证固定长度
            hash_value = hash(str(self.value)) & 0x7FFFFFFFFFFFFFFF  # 63位正数
            return struct.pack('<Q', hash_value)
        else:
            raise ValueError(f"Unsupported key type: {self.key_type}")
    
    @classmethod
    def from_bytes(cls, data: bytes, key_type: str, original_value: Any = None):
        """从字节序列创建索引键"""
        if key_type == 'int':
            value = struct.unpack('<Q', data)[0]
        elif key_type == 'float':
            value = struct.unpack('<d', data)[0]
        elif key_type == 'string':
            # 字符串类型需要原始值，因为哈希不可逆
            if original_value is None:
                raise ValueError("String key requires original value for reconstruction")
            value = original_value
        else:
            raise ValueError(f"Unsupported key type: {key_type}")
        
        return cls(value=value, key_type=key_type)
    
    def __lt__(self, other):
        """支持键的比较"""
        if not isinstance(other, IndexKey):
            return NotImplemented
        
        if self.key_type != other.key_type:
            raise ValueError("Cannot compare keys of different types")
        
        return self.value < other.value
    
    def __eq__(self, other):
        """支持键的相等比较"""
        if not isinstance(other, IndexKey):
            return False
        
        return self.key_type == other.key_type and self.value == other.value
    
    def __hash__(self):
        """支持键作为字典键"""
        return hash((self.value, self.key_type))


@dataclass 
class RecordPointer:
    """记录指针，指向数据页面中的具体记录"""
    page_id: int                      # 页面ID
    slot_id: int                      # 页面内记录槽位ID
    
    def to_bytes(self) -> bytes:
        """转换为字节序列"""
        return struct.pack('<II', self.page_id, self.slot_id)
    
    @classmethod
    def from_bytes(cls, data: bytes):
        """从字节序列创建记录指针"""
        page_id, slot_id = struct.unpack('<II', data)
        return cls(page_id=page_id, slot_id=slot_id)


@dataclass
class IndexEntry:
    """索引项定义"""
    key: IndexKey                     # 索引键
    pointer: Union[RecordPointer, int]  # 记录指针（叶子节点）或页面ID（内部节点）
    
    def to_bytes(self) -> bytes:
        """转换为字节序列"""
        key_bytes = self.key.to_bytes()
        
        if isinstance(self.pointer, RecordPointer):
            pointer_bytes = self.pointer.to_bytes()
        else:
            # 页面ID，使用4字节
            pointer_bytes = struct.pack('<I', self.pointer) + b'\x00\x00\x00\x00'
        
        return key_bytes + pointer_bytes
    
    @classmethod
    def from_bytes(cls, data: bytes, key_type: str, is_leaf: bool, original_key_value: Any = None):
        """从字节序列创建索引项"""
        key_bytes = data[:INDEX_CONSTANTS['KEY_SIZE']]
        pointer_bytes = data[INDEX_CONSTANTS['KEY_SIZE']:INDEX_CONSTANTS['KEY_SIZE'] + INDEX_CONSTANTS['RECORD_ID_SIZE']]
        
        key = IndexKey.from_bytes(key_bytes, key_type, original_key_value)
        
        if is_leaf:
            pointer = RecordPointer.from_bytes(pointer_bytes)
        else:
            pointer = struct.unpack('<I', pointer_bytes[:4])[0]
        
        return cls(key=key, pointer=pointer)


@dataclass
class IndexMetadata:
    """索引元数据"""
    index_name: str                   # 索引名称
    table_name: str                   # 表名
    column_name: str                  # 列名
    index_type: IndexType             # 索引类型
    key_type: str                     # 键数据类型
    root_page_id: int                 # 根页面ID
    height: int                       # 树的高度
    entry_count: int                  # 索引项数量
    
    def to_bytes(self) -> bytes:
        """序列化为字节序列"""
        # 使用JSON序列化，简化实现
        import json
        data = {
            'index_name': self.index_name,
            'table_name': self.table_name,
            'column_name': self.column_name,
            'index_type': self.index_type.value,
            'key_type': self.key_type,
            'root_page_id': self.root_page_id,
            'height': self.height,
            'entry_count': self.entry_count
        }
        json_str = json.dumps(data)
        json_bytes = json_str.encode('utf-8')
        
        # 前4字节存储长度
        length_bytes = struct.pack('<I', len(json_bytes))
        return length_bytes + json_bytes
    
    @classmethod
    def from_bytes(cls, data: bytes):
        """从字节序列反序列化"""
        import json
        
        length = struct.unpack('<I', data[:4])[0]
        json_bytes = data[4:4+length]
        json_str = json_bytes.decode('utf-8')
        data_dict = json.loads(json_str)
        
        return cls(
            index_name=data_dict['index_name'],
            table_name=data_dict['table_name'],
            column_name=data_dict['column_name'],
            index_type=IndexType(data_dict['index_type']),
            key_type=data_dict['key_type'],
            root_page_id=data_dict['root_page_id'],
            height=data_dict['height'],
            entry_count=data_dict['entry_count']
        )


# 异常类定义
class IndexException(Exception):
    """索引系统异常基类"""
    pass


class IndexNotFound(IndexException):
    """索引不存在异常"""
    pass


class DuplicateKeyException(IndexException):
    """重复键异常"""
    pass


class IndexCorruptedException(IndexException):
    """索引损坏异常"""
    pass
